#ifndef __TwEntity_H__
#define __TwEntity_H__

#include "TwDefines.h"
#include "TwSceneNode.h"
#include "TwMovableObject.h"
#include "TwMesh.h"
#include "TwSubEntity.h"
#include "TwSkeleton.h"
#include "TwAnimation.h"
#include "TwAxisAlignedBox.h"
#include "TwDummyObject.h"
#include "TwRenderable.h"
#include <string>
#include <map>

class TwEntity : public TwMovableObject, public TwRenderable
{
public:
	union FrameList
	{
	   TwSkeletalAnimation*				skeletonFrames;
	   TwMeshAnimation*					meshFrames;

	   FrameList()	: skeletonFrames(NULL), meshFrames(NULL) {}
	};
	struct AnimationSet
	{
		TwAnimation*	animation;
		FrameList		frames;

		AnimationSet() { animation = TwNew TwAnimation; }
		~AnimationSet() { TwSafeDelete(animation); }
	};

	typedef std::map<std::string, TwDummyObject*> ChildObjectMap;
	typedef ChildObjectMap::iterator ChildObjectIterator;
	typedef ChildObjectMap::const_iterator ConstChildObjectIterator;
	typedef ChildObjectMap::value_type ChildObjectValue;

public:
	TwEntity(TwMesh* mesh);
	virtual ~TwEntity();

	static TwEntity*	createEntity(LPCSTR filename);

	virtual void		setAttached(TwSceneNode* parent);

	virtual void		attachSkeleton(TwSkeleton* skeleton);
	virtual bool		hasAnimation();

	virtual float		getAlpha() const;
	virtual void		setAlpha(float alpha);

	virtual void		render(TwCamera* camera, TimeValue t);

	virtual void		setAnimation(const std::string& name);
	virtual void		playAnimation(TimeValue t, bool loop = true);
	virtual void		setAnimationSpeed(float speed);
	virtual void		stopAnimation();

	virtual const		TwAxisAlignedBox& getWorldBoundingBox(bool derive = false);
	virtual const		TwAxisAlignedBox& getBoundingBox();

	virtual TwSceneNode* getChildObject(const std::string& name);

	TwMesh*				getMesh();

	virtual void		_updateRenderQueue(TwRenderQueue* queue, TwCamera* cam);
	virtual float		getSquaredViewDepth(TwCamera* cam) const;

protected:
	virtual void		buildSubEntityList();
	virtual void		buildChildObjects();
	virtual void		updateAnimation(TimeValue t);
	virtual void		_setRenderStates();
	virtual void		_resetRenderStates();

	virtual void		_notifyAttached(TwSceneNode* parent);
	virtual void		_notifySkeletonAttached(TwSkeleton* skeleton);
	virtual TwAxisAlignedBox getChildWorldBoundingBox();

protected:
	TwMesh*				mMesh;
	AnimationSet*		mAnimation;
	
	TwSubEntityList		mSubEntityList;
	ChildObjectMap		mChildObjectList;

	TwAxisAlignedBox	mFullBoundingBox;

	float				mAlpha;

	// vertex blend mode(whether to use software processing), only used when the entity
	// has a skeleton attached
	bool				mUseSoftwareVP;
};

#endif //__TwEntity_H__